App.tsx,跑起開發伺服器# 1) 建立 Vite + React + TS 專案
npm create vite@latest resume-site-react -- --template react-ts
# 2) 安裝依賴
cd resume-site-react
npm install
# 3) 啟動開發伺服器
npm run dev
打開瀏覽器(預設 http://localhost:5173)能看到 React 初始頁就成功了。
resume-site-react/
├─ index.html              # 整站入口
├─ src/
│  ├─ App.tsx              # 根元件
│  ├─ main.tsx             # React 入口
│  ├─ components/          # 共用元件
│  ├─ styles/              # 全域 CSS
│  └─ assets/              # 圖片
└─ tsconfig.json
先放一份全域 CSS,方便骨架套用。
src/styles/base.css* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; font-family: system-ui, -apple-system, "Noto Sans TC", Arial, sans-serif; line-height: 1.7; }
img { max-width: 100%; height: auto; display: block; }
a  { color: inherit; text-decoration: none; }
.container { max-width: 960px; margin: 0 auto; padding: 0 16px; }
.section { padding: 56px 0 40px; }
.muted { color: #6b7280; }
.btn { display:inline-block; padding:10px 16px; background:#2563eb; color:#fff; border:1px solid #2563eb; border-radius:8px; cursor:pointer; }
.btn:hover { opacity:.92; }
.btn-outline { background:transparent; color:#2563eb; border-color:#2563eb; }
.btn.small { padding:6px 10px; font-size:14px; }
.site-header { position:sticky; top:0; background:#fff; border-bottom:1px solid #e5e7eb; z-index:10; }
.site-header .container { display:flex; align-items:center; gap:16px; padding:12px 16px; }
.brand { font-weight:700; }
.site-nav { margin-left:auto; }
.site-nav ul { list-style:none; margin:0; padding:0; display:flex; gap:12px; }
.site-nav a:hover { color:#2563eb; }
.hero { display:grid; gap:20px; padding:40px 0; }
.hero-text h1 { margin:8px 0 6px; font-size: clamp(24px, 5vw, 34px); }
.hero-cta { display:flex; gap:12px; margin-top:8px; }
.hero-photo { max-width:240px; }
.hero-photo img { border-radius:50%; border:4px solid #e5e7eb; }
.skill-grid, .project-grid { display:grid; gap:12px; }
.skill-grid { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); list-style:none; padding:0; }
.skill-grid li { border:1px solid #e5e7eb; padding:10px 12px; border-radius:10px; }
.project-grid { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.card { border:1px solid #e5e7eb; border-radius:12px; padding:16px; }
.site-footer { margin-top:48px; border-top:1px solid #e5e7eb; }
.site-footer .container { padding:16px; text-align:center; color:#6b7280; }
在 src/main.tsx 引入:
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import './styles/base.css'
ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)
在 src/components/ 下建立 7 個檔案:
SiteHeader.tsx
Hero.tsx
About.tsx
Skills.tsx
Projects.tsx
Contact.tsx
SiteFooter.tsx
src/components/SiteHeader.tsximport React from 'react'
export default function SiteHeader() {
  return (
    <header className="site-header">
      <div className="container">
        <a className="brand" href="#home">Chiayu</a>
        <nav className="site-nav">
          <ul>
            <li><a href="#about">關於我</a></li>
            <li><a href="#skills">技能</a></li>
            <li><a href="#projects">作品</a></li>
            <li><a href="#contact">聯絡</a></li>
          </ul>
        </nav>
      </div>
    </header>
  )
}
其他元件可以先做靜態版:
src/components/Hero.tsximport React from 'react'
export default function Hero() {
  return (
    <section className="hero container" id="home">
      <div className="hero-text">
        <h1>哈囉,我是 Chiayu</h1>
        <p>前端工程師|專長 React / Vue / Angular / TypeScript</p>
        <div className="hero-cta">
          <a className="btn" href="#projects">看作品</a>
          <a className="btn btn-outline" href="#contact">聯絡我</a>
        </div>
      </div>
      <div className="hero-photo">
        <img src="/assets/me-formal.jpg" alt="Chiayu 的照片" width="240" height="240" />
      </div>
    </section>
  )
}
About.tsx / Skills.tsx / Projects.tsx / Contact.tsx / SiteFooter.tsx 都先放靜態 HTML 骨架(和 Vue/Angular 對齊),後面幾天再逐步「資料化」、「加互動」。
import React from 'react'
import SiteHeader from './components/SiteHeader'
import Hero from './components/Hero'
import About from './components/About'
import Skills from './components/Skills'
import Projects from './components/Projects'
import Contact from './components/Contact'
import SiteFooter from './components/SiteFooter'
export default function App() {
  return (
    <><SiteHeader />
      <main>
        <Hero />
        <About />
        <Skills />
        <Projects />
        <Contact />
      </main>
      <SiteFooter />
    </>
  )
}
npm run dev,看到完整骨架頁面忘了引入 CSS → 畫面全白
✅ 確認 main.tsx 有 import './styles/base.css'
JSX 語法錯誤 → 例如 class 改成 className
✅ React 中要用 className、htmlFor 等
圖片路徑錯誤 → 確認放在 public/assets/,存取 /assets/...
我們要把靜態骨架 資料化:
useState 管理 Skills / Projects 陣列.map() 取代硬寫列表